#!/usr/bin
# -*- coding: utf-8 -*-

import mod_parameters as params
import mod_problem as pr
import mod_node as nd
import mod_element as el
import mod_section as sec
import mod_material as mat
import mod_domain as dom

TCI = params.PARAMS["testConstructorsInputs"]

# ==============================================================================
class ParserDat():
    """ This generic class describes the data structure a parser must create
    in order to match the finite element requirements
    """
    NAME = "Parser for dat files"
    FILE_EXTENSION = ".dat"
    COMMENT_CHARACTER = "#"
    NAME_VALUE_SEPARATOR = "="

    def __init__(self):
        self.nds = []
        self.els = []
        self.doms = []
        self.topDoms = []
        self.secs = []
        self.mats = []
        self.bcs = []
        self.lcs = []

    def readFile(self, fileName):
        """ This function reads the input file data structure.
        The formating of this data structure to the one of iCafe
        is the role of the self.finilizeDataStructure() method.
        """
        try:
            file = open(fileName, "r")
        except:
            raise InputError, "Can not open " + fileName

        iLine = 0
        while True:
            line = file.readline()
            if not line:
                break
            iLine += 1
            line = line.replace("\n", "")
            line = line.replace("\r", "")
            line = line.replace(" ", "")
            if len(line) > 0:
                # this is not a blank line
                if line[0] != ParserDat.COMMENT_CHARACTER:
                    # this is not a comment line
                    line = line.split(",")
                    keyword = line[0].lower()

                    if keyword == "n":
                        self.readNode(line, iLine)

                    elif keyword == "e":
                        self.readElement(line, iLine)

                    elif keyword == "d":
                        self.readDomain(line, iLine)

                    elif keyword == "td":
                        self.readTopologicDomain(line, iLine)

                    elif keyword == "s" :
                        self.readSection(line, iLine)

                    elif keyword == "m":
                        self.readMaterial(line, iLine)

                    elif keyword == "bc":
                        self.readBoundaryCondition(line, iLine)

                    elif keyword == "lc":
                        self.readLoadCondition(line, iLine)

                    else:
                        raise ValueError, "Line " + str(iLine) + \
                                          ": unknown keyword " + keyword
        file.close()

    def readNode(self, line, iLine):
        # file    : n, userId, x, y, z
        uId = line[1]
        try:
            x, y, z = float(line[2]), float(line[3]), float(line[4])
        except:
            raise ValueError, "Line " + str(iLine) + \
                              ": can not convert coordinates into floats."
        self.nds.append((uId, x, y, z))

    def readElement(self, line, iLine):
        # file: e, type, sectionUserId, userId, nodesUserIds
        typ = line[1]
        secUId = line[2]
        uId = line[3]
        ndsUIds = line[4:]
        self.els.append((uId, typ, ndsUIds))

    def readSection(self, line, iLine):
        # file: s, type, userId, materialUserId, params=values
        typ = line[1]
        uId = line[2]
        matUId = line[3]
        params = {}
        for p in line[4:]:
            p = p.split(ParserDat.NAME_VALUE_SEPARATOR)
            params[p[0].lower()] = p[1]
        self.doms.append((uId, typ, matUId, params))

    def readMaterial(self, line, iLine):
        # file: m, userId, type, params=values
        typ = line[1]
        uId = line[2]
        params = {}
        for p in line[3:]:
            p = p.split(ParserDat.NAME_VALUE_SEPARATOR)
            params[p[0].lower()] = p[1]
        self.mats.append((uId, typ, params))

    def readDomain(self, line, iLine):
        # file: d, userId, elementsUserIds
        uId = line[1]
        elsUIds = line[2:]
        self.doms.append((uId, elsUIds))

    def readTopologicDomain(self, line, iLine):
        # file: d, domainUserId, cornerNodesUserIds
        domUId = line[1]
        cornerNodesUIds = line[2:]
        self.topDoms.append((domUId, cornerNodesUIds))

    def readBoundaryCondition(self, line, iLine):
        # file: bc, nodeUserId, firstDofId, lastDofId, dofValue 
        ndUId = line[1]
        fstDofId = line[2]
        lstDofId = line[3]
        dofVal = line[4]
        self.bcs.append((ndUId, fstDofId, lstDofId, dofVal))

    def readLoadCondition(self, line, iLine):
        # file: lc, nodeUserId, firstDualId, lastDualId, dualValue 
        ndUId = line[1]
        fstDualId = line[2]
        lstDualId = line[3]
        dualVal = line[4]
        self.lcs.append((ndUId, fstDualId, lstDualId, dualVal))

    def buildCodeDataStructure(self, problem):
        """ This function makes the interface between the input file
        data structure and iCafe data structure."""
        if TCI:
            if not isinstance(problem, pr.Problem):
                raise ValueError, "A Problem object is need to build " + \
                                  "the code data structure."



# ==============================================================================
if __name__ == "__main__":
    parser = ParserDat()
    fileName = "maillage5.dat"
    parser.readFile(fileName)
